#ifndef _CRT_SJSON_H_
#define _CRT_SJSON_H_

#include <crt_core.hpp>

#ifdef __cplusplus
extern "C" {
#endif

#define sjson_false S_ERROR
#define sjson_true  S_SUCCESS

#define sjson_invalid (0)
#define sjson_raw     (1 << 0)
#define sjson_int64   (1 << 1)
#define sjson_int     (1 << 2)
#define sjson_double  (1 << 3)
#define sjson_string  (1 << 4)
#define sjson_array   (1 << 5)
#define sjson_obj     (1 << 6)

#define sjson_is_invalid(m) ((m->type & 0xFF) == sjson_invalid ? sjson_true : sjson_false)

#define sjson_is_raw(m) ((m->type & 0xFF) == sjson_raw ? sjson_true : sjson_false)

#define sjson_is_int(m) ((m->type & 0xFF) == sjson_int ? sjson_true : sjson_false)

#define sjson_is_double(m) ((m->type & 0xFF) == sjson_double ? sjson_true : sjson_false)

#define sjson_is_string(m) ((m->type & 0xFF) == sjson_string ? sjson_true : sjson_false)

#define sjson_is_array(m) ((m->type & 0xFF) == sjson_array ? sjson_true : sjson_false)

#define sjson_is_obj(m) ((m->type & 0xFF) == sjson_obj ? sjson_true : sjson_false)

#ifndef sjson_nesting_limit
#define sjson_nesting_limit 10240
#endif

#pragma pack(push, 4)

typedef struct sjson sjon;

typedef struct sjson {
    struct sjson* next;
    struct sjson* prev;
    struct sjson* child;

    int type;
    char* key;

    int64 valueint64;
    int valueint;
    double valuedouble;
    char* valuestring;

} sjson;

typedef sjson* sjsonptr;
typedef const sjson* sjsoncptr;
typedef sjson* const sjsonvptr;
typedef const sjson* const sjsoncvptr;

#pragma pack(pop)

sjsonptr sjson_parse(const char* value, unsigned long len, int fmt);
char* sjson_print(sjsoncptr item, unsigned long len, int fmt);
sjsonptr sjson_get_array_item(sjsoncptr array, int index);

int sjson_delete_item(sjsonptr parent, sjsonvptr item);
int sjson_delete(sjsonptr c);
int sjson_replace_item(sjsonvptr parent, sjsonvptr item, sjsonptr replace);
int sjson_add_array(sjsonptr array, sjsonptr item);
int sjson_add_obj(sjsonptr object, const char* key, sjsonptr item);
int sjson_insert_array(sjsonptr array, unsigned int index, sjsonptr newitem);
int sjson_get_array_size(sjsoncptr array);
int sjson_compare(sjsoncvptr a, sjsoncvptr b);

sjsonptr sjson_duplicate(sjsoncptr item);
sjsonptr sjson_get_obj(sjsoncvptr obj, const char* const key);

sjsonptr sjson_create_array(void);
sjsonptr sjson_create_obj(void);

sjsonptr sjson_create_int(int value);
sjsonptr sjson_create_double(double value);
sjsonptr sjson_create_string(const char* value);

sjsonptr sjson_create_int_array(const int* values, unsigned int count);
sjsonptr sjson_create_double_array(const double* values, unsigned int count);
sjsonptr sjson_create_string_array(const char** values, unsigned int count);

void* sjson_allocate(size_t size);
void* sjson_reallocate(void* addr, size_t size);
void sjson_deallocate(void* obj);
void sjson_format(char* json);

#ifdef __cplusplus
}
#endif

#endif
